Skip to content

Custom Web Dashboard - #4707

Open
cagnulein wants to merge 19 commits into
masterfrom
feature/custom-web-dashboard
Open

Custom Web Dashboard#4707
cagnulein wants to merge 19 commits into
masterfrom
feature/custom-web-dashboard

Conversation

@cagnulein

Copy link
Copy Markdown
Owner

No description provided.

cagnulein and others added 3 commits June 9, 2026 09:58
Add a new setting in UI Options that lets users replace the QZ home
screen with any web dashboard served by the existing local webserver.
The QtWebView overlay sits below the top toolbar (keeping start/stop
controls always visible) and follows the same pattern already used by
the Workout Editor, so it works on iOS, Android and desktop without
extra dependencies.

Built-in 'bike-pro' dashboard: Apple-style dark design with live
power/cadence/speed tiles, a 7-zone power bar that reacts to FTP ratio,
a 60-second rolling Chart.js graph, and heart rate / distance / kcal
at the bottom. All data comes through the existing WebSocket feed.

User dashboards: place files in <appdata>/dashboards/<name>/index.html
and they appear automatically in the picker. Community dashboards can
be distributed as a simple zip.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The guide (docs/custom-dashboard-guide.md) covers file layout, qml.qrc
registration, shared asset paths, the WebSocket API with the correct
{msg:"workout", content:{...}} envelope, full metric field reference for
all device types, control commands, power zone table, minimal example,
and a distribution checklist.

Also fixes the WS message parser in bike-pro/app.js: data lives in
msg.content, not at the message root level.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@cagnulein

Copy link
Copy Markdown
Owner Author

@Qhilm do you like the idea?

github-actions Bot and others added 13 commits June 9, 2026 08:19
Automatic update of translatable strings extracted from source code.
Updated 30 language files in src/translations/

- Updated by GitHub Actions (Testing Mode)
- Triggered by: pull_request
- Date: 2026-06-09 08:19:11 UTC
Apple-style dark dashboard for treadmill workouts, inspired by the QZ
Fitness home screen. Highlights:

- Speed hero (1fr): large current speed with colour coding relative to
  target (blue = under, green = on target, orange = over), Avg + Max
  (session-tracked client-side)
- Target speed bar: fill shows current vs target with an orange marker
  at the target value — only visible when a training program is active
- Training program header (collapses to 0-height when no workout is
  loaded): workout name, step badge, target speed/incline chips, overall
  session progress bar, and row countdown timer
- 4 metric tiles: Pace (min/km), Incline (%), Cadence (spm), Heart Rate
  with intensity colour coding (blue/green/orange/red)
- Bottom row: Distance, Watts, Calories

Connects to the same QZ WebSocket feed as the other dashboards
({msg:"workout", content:{...}}), auto-reconnects on disconnect.
Grid layout uses explicit grid-row assignments so the program header
collapsing to height:0 does not disrupt the 1fr speed-hero row.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Complete rewrite of all three files to replace the flat/bland layout with
a neon cyberpunk sports HUD:
- Dark background (#07070f) with subtle scanline overlay
- 96px neon-green speed number with animated glow (shifts orange/teal vs target)
- Canvas sparkline with bezier waveform, gradient fill, glowing dot tip,
  and dashed orange target-speed line
- Radial ambient glow behind speed that reacts to over/under target state
- 4 metric tiles with individual coloured top accent bars + glow shadows
  (teal=pace, orange=incline, purple=cadence, red=HR)
- Pulsing heart icon animation; HR value colour-codes by zone
- Program header with teal glow title, blue pill STEP badge, progress bar
  with animated gradient fill and glowing leading dot
- Fixed status bar (LIVE dot / elapsed / connection) above grid via padding-top

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full restructure to mirror the actual QZ Fitness app layout:
- Timeline strip at top with animated runner indicator and progress bar
- Interval info row: workout name + "Interval N" badge + detail line
  (target speed / grade / distance)
- Speed section: large number LEFT + live bezier waveform canvas RIGHT
  (speed shifts teal=under / white=on / orange=over target)
- 2x2 metric grid: Cadence | AVG Watt / Heart Rate | Total KCal
  (HR value colour-codes by zone, pulsing heart icon)
- Odometer row with distance
- Status bar: device name / total elapsed / connection state

Dark navy (#13161e) surface-card aesthetic matching the app screenshot.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Re-add the IndicatorOnlySwitch + description label + ComboBox (populated
via rootItem.availableDashboards()) + OK button that were lost from the
General UI Options accordion. The two backing properties
(ui_custom_dashboard_enabled, ui_custom_dashboard_name) were already
present in the Settings {} block — only the visible controls were missing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The controls were erroneously inserted inside the Zwift Options accordion
instead of General UI Options. Moved to the correct ColumnLayout with
proper brace nesting (missing closing } for ColumnLayout also fixed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Qhilm

Qhilm commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

@Qhilm do you like the idea?

I mean, it's hard to tell before testing it, but in theory this is super flexible, meaning someone can move away from the built-in tiles and define whatever one wants. Is my understanding correct?

If that's the case, then yes, it's pretty cool. The tiles are quite inflexible and on my iPhone 12 Mini, the screen real estate is not well utilized, there's a lot of white space. Hence being able to design my own dashboard would be indeed pretty cool =)

@cagnulein

Copy link
Copy Markdown
Owner Author

@Qhilm do you like the idea?

I mean, it's hard to tell before testing it,

yeah i know :D

but in theory this is super flexible, meaning someone can move away from the built-in tiles and define whatever one wants. Is my understanding correct?

exactly! I also added the guidelines for any LLM to create your own dashboard with a simple prompt

If that's the case, then yes, it's pretty cool. The tiles are quite inflexible and on my iPhone 12 Mini, the screen real estate is not well utilized, there's a lot of white space. Hence being able to design my own dashboard would be indeed pretty cool =)

yes indeed :) i make this in order that users can also share the dashboard created so we can have a sort of repository with images :)

@Qhilm

Qhilm commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Then I think it's a very nice idea. Focus should be on elegant dynamic resizing so dashboards work on different screen sizes.

The rounded corners and the notches / Dynamic Islands / etc. of smartphones would need some form of consideration maybe, not sure how complex this is.

@cagnulein

Copy link
Copy Markdown
Owner Author

it's something that the user should plan, i mean, from the qz side would be just a web view that talks with the back end. So all the UI customization is in the hand of the users. Let's see how it goes!

cagnulein and others added 2 commits June 11, 2026 15:46
The Loader topMargin was set to topBarHeight (120px), leaving the
Start/Stop/Lap toolbar row exposed above the WebView. The app's global
navigation ToolBar (hamburger/left-sidebar access) is in main.qml's
header: property and sits outside the Page coordinate space, so setting
topMargin: 0 gives the dashboard full coverage of the page content while
the navigation bar remains untouched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
QtWebView does not automatically reflow the viewport on rotation.
Subscribe to Screen.onPrimaryOrientationChanged and reload by clearing
and restoring the URL, which forces a fresh layout pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Qhilm

Qhilm commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

I meant, let's say I'm building a dashboard. How can I say "keep 2mm or X pixels distance from the notch for this element but that element is decorative, it can can go 'under' the notch". Is that even technically possible?

Not a deal breaker, but would be nice.

@cagnulein

Copy link
Copy Markdown
Owner Author

consider that qz is running under the dynamic island so you don't need to care about this :)

- main.qml: expose sideBarVisible property, set true/false on
  drawer onOpened/onClosed so Home.qml can hide the WebView
- Home.qml: bind Loader visible to !window.sideBarVisible so the
  native WebView doesn't occlude the drawer (QtWebView renders as a
  native view outside QML z-ordering)
- homeform.cpp: exclude internal templates (chartjs, googlemaps,
  maps2d, floating, previewchart, workouteditor, workoutpreview,
  trainingbrowser) from availableDashboards() — only user-facing
  dashboards appear in settings
- treadmill-pro: full redesign matching QZ app screenshot layout:
  current segment name (large teal), stats row (dist/time/avgspeed),
  progress bar, sparkline + lap stats (pace/HR/cadence), interactive
  speed ±  and incline ± control rows, Next Lap / Pause action buttons
  Responsive CSS for landscape orientation via @media query

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@stale

stale Bot commented Jun 27, 2026

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale Bot added the wontfix This will not be worked on label Jun 27, 2026
@stale stale Bot closed this Jul 5, 2026
@cagnulein cagnulein reopened this Jul 6, 2026
@stale stale Bot removed the wontfix This will not be worked on label Jul 6, 2026
@stale

stale Bot commented Jul 24, 2026

Copy link
Copy Markdown

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale Bot added the wontfix This will not be worked on label Jul 24, 2026
@stale stale Bot closed this Aug 1, 2026
@cagnulein cagnulein reopened this Aug 1, 2026
@stale stale Bot removed the wontfix This will not be worked on label Aug 1, 2026
@stale stale Bot closed this Aug 8, 2026
@cagnulein cagnulein reopened this Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants